#pragma once

#include "..\\Vertex.h"
#include <dae.h>
#include <dom.h>
#include <dom/domCOLLADA.h>
#include "ColladaLibs.h"
#include <string>
#include <vector>
using namespace std;

#include "..\\..\\Utility\\D3D\\D3DUtilityFunction.h"
#include "..\\MeshRender.h"

template <class CVertType>
class StaticMesh : public CMeshRender
{
public:
#pragma region //COLLADA members
	//<geometry> element to get mesh data from
	daeElement* geometry;

	//Component Vertex Data, to be compiled into Vertices later...
	vector<D3DXVECTOR3> Positions;
	vector<D3DXVECTOR2> UVs;
	vector<D3DXVECTOR3> Normals;
	vector<D3DXVECTOR3> Tangents;
	vector<D3DXVECTOR3> BiNormals;

	//Set it so COLLADALoader can access privates
	//friend class COLLADALoader;

	//Combine the component vertex data to Vertices array
	void combineComponents()
	{
		for(unsigned int i = 0; i < Positions.size(); i++)
		{
			switch (m_iVType)
			{
			case (VERTEXTYPE::VT_POS):
				CVertType::AddIntoArray(Vertices, &(Positions[i]),NULL,NULL,NULL,NULL);
				break;
			case (VERTEXTYPE::VT_POSNORM):
				CVertType::AddIntoArray(Vertices,&(Positions[i]),&(Normals[i]),NULL,NULL,NULL);
				break;
			case (VERTEXTYPE::VT_POSNORMUV):
				CVertType::AddIntoArray(Vertices, &(Positions[i]),&(Normals[i]),&(UVs[i]),NULL,NULL);
				break;
			case (VERTEXTYPE::VT_POSNORMUVTANG):
				CVertType::AddIntoArray(Vertices, &(Positions[i]),&(Normals[i]),&(UVs[i]),&(Tangents[i]),&(BiNormals[i]));
				break;
			}				
		}
	}
#pragma endregion
	//Set access rights
	//friend class MorphingMesh<CVertType>;
public:
	//Name of this mesh
	string Name;
	//Combined Vertex Data, ready for Vertex Buffer
	vector<CVertType> Vertices;
	//Index data, ready for Index Buffer
	vector<unsigned int> Indices;

	//Constructor
	StaticMesh():CMeshRender()
	{
		//Set Name
		this->Name = string("default");

		//Set Vertex Type
		m_iVType = CVertType::VType;
		STRIDE_SIZE = CVertType::STRIDE_SIZE;
		printf("The VType of the mesh is: %s\n", VERTEXTYPENAME[m_iVType]);

		//Initialize Component Vertex Data arrays
		Positions = vector<D3DXVECTOR3>();
		UVs = vector<D3DXVECTOR2>();
		Normals = vector<D3DXVECTOR3>();
		Tangents = vector<D3DXVECTOR3>();
		BiNormals = vector<D3DXVECTOR3>();

		//Initialize Combined Vertex Data array
		Vertices = vector<CVertType>();
		//Initialize Index Data Array
		Indices = vector<unsigned int>();
		//Initialize COLLADA pointers to NULL
		geometry = NULL;

	}
	StaticMesh(string Name, D3DXMATRIX World):CMeshRender()
	{
		//Set Name
		this->Name = Name;
		//Set World
		this->m_mWorldModel = World;

		//Set Vertex Type
		m_iVType = CVertType::VType;
		STRIDE_SIZE = CVertType::STRIDE_SIZE;
		printf("The VType of the mesh is: %s\n", VERTEXTYPENAME[m_iVType]);

		//Initialize Component Vertex Data arrays
		Positions = vector<D3DXVECTOR3>();
		UVs = vector<D3DXVECTOR2>();
		Normals = vector<D3DXVECTOR3>();
		Tangents = vector<D3DXVECTOR3>();
		BiNormals = vector<D3DXVECTOR3>();

		//Initialize Combined Vertex Data array
		Vertices = vector<CVertType>();
		//Initialize Index Data Array
		Indices = vector<unsigned int>();
		//Initialize COLLADA pointers to NULL
		geometry = NULL;

	}
	//void SetVType(enum VERTEXTYPE VType);
	//Destructor
	virtual ~StaticMesh()
	{   
		OnD3D11DestroyDevice(NULL);

		Positions.clear();
		Normals.clear();
		UVs.clear();
		Tangents.clear();
		BiNormals.clear();
		Vertices.clear();
		Indices.clear();	
	}

	//OnDeviceReset
	HRESULT OnD3D11CreateDevice( ID3D11Device* pd3dDevice, ID3DX11EffectTechnique* pTech,
		const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, CDirectoryUtil* pDirUtil, void* pUserContext)
	{
		HRESULT hr = S_OK;

		//Get vertex buffer size
		if (Vertices.size() == 0)
		{
			printf("No geometry data loaded yet!\n");
#ifdef _DEBUG
			OUTPUTERRORINFO;
#endif
			return E_FAIL;
		}
		//Create vertex layout
		V_RETURN(CD3DUtilityFunction::CreateVertexLayout(pd3dDevice,CVertType::layout,ARRAYSIZE(CVertType::layout),pTech,&m_pVertexLayout));
		//Create VertexBuffer
		V_RETURN(CD3DUtilityFunction::CreateVertexBuffer(pd3dDevice,STRIDE_SIZE, (float*)(Vertices.data()), Vertices.size(), &m_pVB));
		//Create Index Buffer
		V_RETURN(CD3DUtilityFunction::CreateIndexBuffer(pd3dDevice,Indices.size(),(void*)(Indices.data()),&m_pIB));

		return hr;
	}

	//Draw
	void Render(ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext, ID3DX11Effect* pEffect, ID3DX11EffectTechnique* pRenderTech,
		enum RENDERMESHTECH iMeshType, const D3DXMATRIX& mWorldCamera, double fTime, float fElapsedTime, void* pUserContext)
	{
		if(iMeshType != RENDERMESHTECH::RENDERSTATICMESH)
		{
#ifdef _DEBUG
			OUTPUTERRORINFO;
#endif
				return;
		}

		HRESULT hr;
		//Set model world matrix
		D3DXMATRIX mWorldMatrix = m_mWorldModel * mWorldCamera;
		hr = (pEffect->GetVariableByName("mWorld")->AsMatrix()->SetMatrix((float*)(&mWorldMatrix)));
		//HRESULT hr = S_OK;
		// Set render resources
		pd3dImmediateContext->IASetInputLayout( m_pVertexLayout );
		ID3D11Buffer* pVB[1] = { m_pVB };
		UINT pStride[1] = {STRIDE_SIZE};
		UINT pOffset[1] = { 0 };
		pd3dImmediateContext->IASetVertexBuffers( 0, 1, pVB, pStride, pOffset );
		pd3dImmediateContext->IASetIndexBuffer(m_pIB, DXGI_FORMAT_R32_UINT, 0);
		pd3dImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

		// Render objects here...
		// Apply the technique contained in the effect 
		D3DX11_TECHNIQUE_DESC Desc;
		pRenderTech->GetDesc( &Desc );

		for( UINT iPass = 0; iPass < Desc.Passes; iPass++ )
		{
			pRenderTech->GetPassByIndex( iPass )->Apply( 0, pd3dImmediateContext );
			pd3dImmediateContext->DrawIndexed( Indices.size(), 0, 0 );			
		}
	}
};